package edu.neusoft.yiqibike.controller;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.google.common.collect.ImmutableMap;
import edu.neusoft.yiqibike.common.annotation.LoginUser;
import edu.neusoft.yiqibike.common.constant.GlobalConstant;
import edu.neusoft.yiqibike.common.entity.mysql.Admin;
import edu.neusoft.yiqibike.common.entity.mysql.OperationLog;
import edu.neusoft.yiqibike.common.entity.mysql.Role;
import edu.neusoft.yiqibike.common.entity.mysql.SystemDictionary;
import edu.neusoft.yiqibike.common.entity.vo.AdminVo;
import edu.neusoft.yiqibike.common.exception.ArgumentVerifyException;
import edu.neusoft.yiqibike.common.entity.vo.Response;
import edu.neusoft.yiqibike.common.util.*;
import edu.neusoft.yiqibike.service.IAdminService;
import edu.neusoft.yiqibike.service.IAuthorizationService;
import edu.neusoft.yiqibike.service.ISystemDictionaryService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 管理员接口
 * User：lyc
 * Date：2018-01-26
 * Time：17:51
 * Description：
 */
@Slf4j
@RestController
@RequestMapping("/sys/admin")
public class AdminController {
    @Autowired
    private IAdminService adminService;
    @Autowired
    private FileUploadHelper uploadHelper;
    @Autowired
    private ISystemDictionaryService dictionaryService;
    @Autowired
    private IAuthorizationService authorizationService;

    /**
     * 获取管理员列表
     *
     * @param page 分页信息
     * @return 管理员列表
     */
    @PostMapping("/list")
    public Response<Page<Admin>> getAdminList(@RequestBody Page<Admin> page) {
        return Response.success(adminService.getAdminList(page));
    }

    /**
     * 获取指定ID的管理员信息
     *
     * @param aid 管理员ID
     * @return 管理员信息
     */
    @GetMapping("/{id}")
    public Response<Admin> getAdminById(@PathVariable(name = "id") Long aid, HttpServletRequest request) {
        return Response.success(adminService.getAdminById(aid));
    }

    /**
     * 添加管理员账号
     *
     * @param admin 管理员
     * @return 操作成功
     */
    @PostMapping("/add")
    public Response<String> addAdmin(@RequestBody Admin admin) {
        adminService.addAdmin(admin);
        return Response.success();
    }

    /**
     * 登录（测试账号 test:123456）
     *
     * @param admin         管理员账号信息
     * @param bindingResult 非空条件校验
     * @return 登录成功
     */
    @PostMapping("/login")
    public Response<Map<String, Object>> login(@Valid @RequestBody Admin admin, BindingResult bindingResult) {
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(new UsernamePasswordToken(admin.getRealname(), admin.getPassword()));
        } catch (IncorrectCredentialsException e) {
            throw new IncorrectCredentialsException("请输入正确的账号与密码！");
        }
        admin = (Admin) subject.getPrincipal();
        subject.getSession().setTimeout(1000 * 60 * 60 * 3);
        //获取当前登录管理员的上次登录时间
        OperationLog operationLog = new OperationLog().selectOne(new EntityWrapper().eq("uid", admin.getId())
                .eq("method", "login").orderBy("create_time", false));
        if (Objects.isNull(operationLog)) {
            return Response.success(ImmutableMap.of("admin", admin));
        }
        Date createTime = operationLog.getCreateTime();
        String lastLoginTime = DateTimeUtil.dateTime2String(createTime, "yyyy-MM-dd HH:mm:ss");
        return Response.success(ImmutableMap.of("admin", admin, "lastLoginTime", lastLoginTime));
    }

    /**
     * 获取当前登录的管理员信息
     *
     * @param admin 当前登录的管理员
     * @return 管理员信息
     */
    @GetMapping("/info")
    public Response<AdminVo> getLoginAdmin(@LoginUser Admin admin) {
        if (Objects.isNull(admin)) {
            throw new AuthenticationException("当前处于未登录状态");
        }
        admin = admin.selectById();
        //pojo->vo
        AdminVo vo = new AdminVo();
        MapperUtil.getInstance().map(admin, vo);
        //数据字典转换
        SystemDictionary department = dictionaryService.getByCodeAndGroupCode(admin.getDepartment(), "departments");
        vo.setBelong(department.getValue());
        SystemDictionary level = dictionaryService.getByCodeAndGroupCode(String.valueOf(admin.getLevel()), "levels");
        vo.setTitle(level.getValue());
        //获取上级领导的姓名
        Admin leader = admin.selectById(admin.getLeaderId());
        if (Objects.nonNull(leader)) {
            vo.setLeader(leader.getRealname());
        }
        //计算工龄
        long seniority = DateTimeUtil.getTimeDifference(admin.getCreateTime(), new Date(), ChronoUnit.DAYS);
        vo.setSeniority(seniority);
        //获取角色信息
        List<Role> roles = authorizationService.getRolesByAid(admin.getId());
        String roleNames = roles.stream().map(Role::getCode).collect(Collectors.joining(","));
        vo.setRoleNames(roleNames);
        return Response.success(vo);
    }

    /**
     * 封禁管理员账号
     *
     * @param admin 管理员账号
     * @return 操作成功
     */
    @PostMapping("/limit")
    public Response<String> limit(@RequestBody Admin admin) {
        if (Objects.isNull(admin) || Objects.isNull(admin.getId()) || Objects.isNull(admin.getIsEnable())) {
            throw new ArgumentVerifyException("检测到非法参数");
        }
        adminService.invertIsEnable(admin.getId(), admin.getIsEnable());
        return Response.success();
    }

    /**
     * 获取指定部门下的人员信息
     *
     * @param department 部门
     * @return 人员信息
     */
    @GetMapping("/colleague/{department}")
    public Response<List<Admin>> getColleagueList(@PathVariable String department) {
        return Response.success(adminService.getColleagueList(department));
    }

    /**
     * 更换管理员头像
     *
     * @param file 头像
     * @return 操作成功
     */
    @PostMapping("/img")
    public Response<String> uploadHeadImage(MultipartFile file) {
        if (file != null && !FileUtil.isImage(file)) {
            throw new IllegalArgumentException("文件格式需为图片且大小在" + GlobalConstant.IMG_DEFAULT_SIZE + "kb以内!");
        }
        String imgUrl = uploadHelper.uploadFile(file);
        if (StringUtils.isEmpty(imgUrl)) {
            return Response.failed("图片上传失败");
        }
        return Response.success(imgUrl);
    }

    /**
     * 修改管理员信息
     *
     * @param admin 管理员信息
     * @return 操作成功
     */
    @PutMapping("/edit")
    public Response<String> editAdmin(@RequestBody Admin admin) {
        admin.updateById();
        return Response.success("管理员信息修改成功");
    }

    /**
     * 修改管理员登录密码
     *
     * @param pwdMap 原密码与新密码
     * @param admin  当前登录的管理员
     * @return 操作成功
     * TODO 敏感操作短信验证码验证身份（activemq）
     */
    @PutMapping("/pwd")
    public Response<String> changePassword(@RequestBody Map<String, String> pwdMap, @LoginUser Admin admin) {
        if (CollectionUtils.isEmpty(pwdMap) || StringUtils.isEmpty(pwdMap.get("newPwd")) || StringUtils.isEmpty(pwdMap.get("oldPwd"))) {
            String msg = "密码不能为空！";
            if (pwdMap.get("newPwd").equals(pwdMap.get("oldPwd"))) {
                msg = "新密码与原密码不能相同";
            }
            throw new ArgumentVerifyException(msg);
        }
        adminService.changePassword(pwdMap.get("newPwd"), pwdMap.get("oldPwd"), admin);
        throw new UnauthenticatedException();
    }
}
